import gradio as gr
import requests
import os
import datetime
import json
import pandas as pd
from pathlib import Path
import re
import logging
from logging.handlers import RotatingFileHandler
from dotenv import load_dotenv
from typing import Generator
from pypdf import PdfReader

# --- 日志配置 ---
LOG_FILE = "app.log"
logging.basicConfig(
    handlers=[RotatingFileHandler(LOG_FILE, maxBytes=1024 * 1024, backupCount=5)],
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S"
)
logger = logging.getLogger(__name__)


def log_event(event_type: str, status: str, details: str = ""):
    """记录系统事件"""
    logger.info(f"[{event_type}] {status} | {details}")


# --- 加载环境变量 ---
load_dotenv(override=True)
TEXTS_DIR = "texts"
RATES_DIR = "rates"
HISTORY_PATH = "history.json"
os.makedirs(TEXTS_DIR, exist_ok=True)
os.makedirs(RATES_DIR, exist_ok=True)


# --- 配置参数 ---
class Config:
    API_URL = "http://10.2.8.77:3000"  # 直接使用DeepSeek API地址
    API_KEY = os.getenv("sk-93nWYhI8SrnXad5m9932CeBdDeDf4233B21d93D217095f22")
    MODEL_NAME = "deepseek-chat"
    MAX_FILE_SIZE_MB = 5
    ALLOWED_EXTENSIONS = [".pdf"]


config = Config()


# --- 历史记录功能 ---
def load_history() -> list:
    try:
        with open(HISTORY_PATH, "r", encoding="utf-8") as f:
            return json.load(f)
    except (FileNotFoundError, json.JSONDecodeError) as e:
        log_event("SYSTEM", "历史记录加载失败", str(e))
        return []


def save_history(history: list) -> None:
    with open(HISTORY_PATH, "w", encoding="utf-8") as f:
        json.dump(history, f, ensure_ascii=False, indent=2)


# --- Helper Functions ---
def sanitize_filename(title: str) -> str:
    sanitized = re.sub(r'[\\/*?:"<>|]', "", title.strip())
    return sanitized[:50]


def safe_save(content: str, directory: str, filename: str) -> str:
    safe_dir = Path(directory).resolve()
    safe_dir.mkdir(exist_ok=True)
    safe_name = sanitize_filename(filename)
    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    save_path = safe_dir / f"{safe_name}_{timestamp}.txt"
    with open(save_path, "w", encoding="utf-8") as f:
        f.write(content)
    return str(save_path)


def validate_pdf_files(files: list) -> None:
    if not files:
        raise ValueError("未上传任何PDF文件")
    for file_info in files:
        file_path = file_info.name
        file = Path(file_path)
        if not file.exists():
            raise ValueError(f"文件不存在: {file_path}")
        if file.suffix.lower() not in config.ALLOWED_EXTENSIONS:
            raise ValueError(f"不支持的文件类型: {file.suffix}")
        if file.stat().st_size > config.MAX_FILE_SIZE_MB * 1024 * 1024:
            raise ValueError(f"文件过大: {file.name} ({file.stat().st_size // 1024 // 1024}MB)")


def extract_text_from_pdf(file_path: str) -> str:
    try:
        reader = PdfReader(file_path)
        text = ""
        for page in reader.pages:
            text += page.extract_text() + "\n"
        return text.strip()
    except Exception as e:
        log_event("ERROR", "PDF解析失败", str(e))
        raise


# --- DeepSeek API调用核心逻辑 ---
def stream_rate_text(content: str) -> Generator[str, None, None]:
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {config.API_KEY}",
        "Accept": "application/json"
    }

    try:
        prompt_path = Path("prompt/basic_evaluation.txt")
        if not prompt_path.exists():
            raise FileNotFoundError("评分模板文件不存在")

        with open(prompt_path, "r", encoding="utf-8") as f:
            prompt_template = f.read()

        payload = {
            "model": config.MODEL_NAME,
            "messages": [
                {"role": "system", "content": "你是一位专业的语文老师，需要根据评分标准对作文进行详细批改"},
                {"role": "user", "content": f"{prompt_template}\n作文内容如下：{content}"}
            ],
            "temperature": 0.7,
            "stream": True
        }

        with requests.post(
                config.API_URL,
                headers=headers,
                json=payload,
                stream=True
        ) as response:
            response.raise_for_status()

            for chunk in response.iter_lines():
                if chunk:
                    decoded_chunk = chunk.decode("utf-8")
                    if decoded_chunk.startswith("data: "):
                        json_data = json.loads(decoded_chunk[6:])
                        if "choices" in json_data:
                            delta = json_data["choices"][0].get("delta", {})
                            if "content" in delta:
                                yield delta["content"]

    except Exception as e:
        log_event("ERROR", "API请求失败", str(e))
        raise


def create_interface():
    with gr.Blocks(
            theme=gr.themes.Soft(),
            title="作文智能批改系统",
            css="""
            .drag-area {
                border: 2px dashed #666;
                border-radius: 10px;
                padding: 20px;
                transition: all 0.3s;
                min-height: 500px;
                position: relative;
            }
            .result-area {
                overflow: visible;
                border: 2px dashed #666;
                border-radius: 10px;
                padding: 10px 10px 0 10px;
                display: flex;
                justify-content: center;
            }
            .drag-area.dragover {
                border-color: #2196F3;
                background: #f5fbff;
            }
            .fixed-height {
                height: 520px;
                overflow: auto;
                box-sizing: border-box;
                border: 3px solid #e0e0e0;
                padding: 10px 10px 0 10px;
                border-radius: 15px;
                font-size: 25px;
                width: 100%;
            }
        """
    ) as demo:  # 注意这里的冒号和后续代码的缩进
        # 这里开始所有界面组件的代码
        # 必须统一缩进4个空格
        history_state = gr.State(value=load_history())
        uploaded_files = gr.State([])

        gr.Markdown("<center><h1>📚 智能作文批改系统</h1></center>")
        gr.Markdown("<center><h3>上传PDF格式作文，自动提取文字并生成批改建议</h3></center>")

        # 剩余界面代码需要保持统一缩进层级...

    return demo  # 注意这个return语句需要在with代码块外


if __name__ == "__main__":
    app = create_interface()
    app.launch(server_name="127.0.0.1", server_port=7860)